package com.hdp.kotlin_samples.middle

/**
 * author:hdp
 * on:2019/6/13:11:59
 * desc:
 *
 * 1、with apply run let 这些函数可以简化我们代码的书写
 *
 * 2、根据具体的使用场景使用，需要关注两点即可!
 *      1）在函数体内，用什么表示自身，是it还是this,如果是this,可以省略掉this访问自身属性和方法
 *      2）函数的返回值是什么，是最后一行表达式的值还是返回自身
 *
 * 3、具体的情形如下
 *      1）使用this指代自身的：with,apply,run
 *      2) 使用it指代自身的：let,also
 *
 *      1) 返回自身的：apply,also
 *      2) 返回最后一行表达式的值的：with,run,let
 *
 *
 * 4、更多：实际上这里的with,apply,run 里面都是带接受者的匿名扩展函数(结合Lambda的特性)，所以在扩展函体内部，可以直接
 *      访问实例对象的属性和方法
 *
 *
 */
fun main() {
    println(test_with())
    println(test_with2())
    println(test_with3())
    println(test_apply1())
    println(test_let())
    println(test_run())
    println(test_also())
}

/**
 *
 * with函数并不是扩展函数，返回值是最后一行，可以直接调用对象的方法
 * Kotlin中可以用with语句来省略同一个变量的多次声明
 *
 * 打印字母表函数，在函数内result变量在好几处有使用到
 */
private fun test_with(): String {
    val result = StringBuilder()
    result.append("START\n")
    for (letter in 'A'..'Z') {
        result.append(letter)
    }
    result.append("\nEND")
    return result.toString()
}


/*
* 通过with语句，将result作为参数传入，在内部就可以通过this来表示result变量了
* */
fun test_with2(): String {
    val result = StringBuilder()
    return with(result) {
        this.append("START\n")
        for (letter in 'A'..'Z') {
            this.append(letter)
        }
        this.append("\nEND")
        this.toString()
    }
}

/*
* 通过with语句，将result参数作为参数，在内部this也可以省略掉
* */
fun test_with3(): String {
    val result = StringBuilder()
    return with(result) {
        append("START\n")
        for (letter in 'A'..'Z') {
            append(letter)
        }
        append("\nEND")
        toString()
    }
}

/*
*apply函数，在函数范围内，可以任意调用该对象的任意方法，并返回该对象
* 用apply语句简化代码，在apply的大括号里可以访问类的公有属性和方法
*/
fun test_apply1(): String {
    return StringBuilder().apply {
        append("START\n")
        for (letter in 'A'..'Z') {
            append(letter)
        }
        append("\nEND")
    }.toString()
}

/**
 * 使用it 代替变量
 * 返回最后一行表达式的结果
 */
private fun test_let(): String? {
    var user: User? = User("dd", 12)
    return user?.let {
        if (it.name == "李四") "lisi" else "zhangsan"
    }
}

/**
 * 使用this代替变量
 * 返回最后一行表达式的结果
 */
private fun test_run(): String? {
    var user: User? = User("李四", 12)
    return user?.run {
        if (name == "李四") "lisi" else "zhangsan"
    }
}

/**
 * 使用also 代替变量
 * 返回最后一行表达式的结果
 */
private fun test_also(): String? {
    var user: User? = User("李四", 12)
    return user?.also {
        if (it.name == "李四") it.name = "lisi" else it.name = "张三"
    }?.name
}